package com.run.wz.center.util;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.io.TimeRange;
import org.apache.hadoop.hbase.util.Bytes;

import com.run.hbase.util.Constant;
import com.run.pbf.Object.ObjectRelation;

/**
 * Description: 对象属性类型枚举 
 * Copyright (c) Department of Research and Development/Beijing/Run.
 * All Rights Reserved.
 * @version 1.0  2012-6-1 下午10:26:05  by 张红意（hongyi@run.com）创建
 */
public enum ObjectType {

	CERTIFICATE_CODE(11) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, PHONENUM(12) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, USERNAME_DOMAIN_PROTOCOLID(13) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	},ACCOUNT(31) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, SRCIP(32) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}
		@Override
		public byte[][] getStartStopRow(String oid) {
			byte[] startRow = Bytes.toBytes(oid);
			byte[] stopRow = Bytes.toBytes(asciiIncrease(oid));
			
			return new byte[][]{startRow,stopRow};
		}
		@Override
		public String getIndexTableNamePrefix() {
			return "actionlog_idx_ip";
		}
		@Override
		public boolean needGroup() {
			return true;
		}
		 

	}, SSID(33) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, SERVICE_CODE(34) {
		//获取查询虚拟身份的时间范围
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			try {
				long minTime = kv.getTimestamp();
				ObjectRelation entity = ObjectRelation.parseFrom(kv.getValue());
				long maxTime = entity.getOfflineTime();
				return new TimeRange(minTime, maxTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

	}, DOMAIN(35) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

		@Override
		public byte[][] getStartStopRow(String oid) {
			byte[] digest = null;
			try {
				String domainstr = StringUtils.substringBefore(oid, Constant.ROWKEY_SEPARATIVE);
				digest = MessageDigest.getInstance("MD5").digest(domainstr.getBytes());
			} catch (NoSuchAlgorithmException e) {
			}
			byte[] startRow = Bytes.add(new byte[]{(byte)this.getNum()}, Bytes.add(Bytes.head(digest, 2), oid.getBytes()));
			byte[] stopRow = Bytes.add(new byte[]{(byte)this.getNum()}, Bytes.add(Bytes.head(digest, 2), Bytes.toBytes(asciiIncrease(oid))));
			
			return new byte[][]{startRow,stopRow};
		}
	}, BSID(36) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	},

	MAC(51) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, SOFT_NUM(52) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, PHONE_IMEI(54) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	}, PHONE_IMSI(55) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}

	},REAL_NAME(28) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}
	},GROUP_ACCOUNT(29) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}
	},REMARK(30) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}
	},RELATION_USERNAME_PROTOCOL(100) {
		@Override
		public TimeRange getRelationObjectTR(KeyValue kv) {
			long uptime = kv.getTimestamp();
			try {
				return new TimeRange(uptime - 20 * 60 * 1000,uptime + 20 * 60 * 1000);
			} catch (IOException e) {
				return null;
			}
		}
	};
	
	private final int objectTypeNum;
	/**
	 * 默认的各类表的表前缀
	 */
	private static final String DEFAULT_LOG_TABLENAME_PREFIX = "actionlog";
	private static final String DEFAULT_OBJINFO_TABLENAME_PREFIX = "object_info";
	
	private ObjectType(int objectTypeNum) {
		this.objectTypeNum = objectTypeNum;
	}

	public int getNum() {
		return this.objectTypeNum;
	}
	
	/**
	 * 根据类型整型值获取对象类型，如果没有获取到会返回 null
	 * @param num
	 * @return
	 */
	public static ObjectType getObjectTypeByNum(int num) {
		ObjectType[] values = ObjectType.values();
		for(ObjectType ot : values) {
			if(ot.getNum()==num) {
				return ot;
			}
		}
		return null;
//		throw new UnSupportObjectTypeException("the num["+num+"] have not ObjectType");
	}
	
	public static class UnSupportObjectTypeException extends RuntimeException {

		/**
		 * 
		 */
		private static final long serialVersionUID = 6135398222303843906L;
		
		/**
	     * Constructs an UnsupportedEncodingException without a detail message.
	     */
	    public UnSupportObjectTypeException() {
	        super();
	    }

	    /**
	     * Constructs an UnsupportedEncodingException with a detail message.
	     * @param s Describes the reason for the exception.
	     */
	    public UnSupportObjectTypeException(String s) {
	        super(s);
	    }
		
	}
	
	/**
	 * 获得关联对象的时间区间，不同对象类型会有不同的实现
	 * @param kv
	 * @return
	 */
	public abstract TimeRange getRelationObjectTR(KeyValue kv);
	/**
	 * 获得这个对象对应的对应的startkey ，stopKey byte数组
	 * @param oid
	 * @return
	 */
	public byte[][] getStartStopRow(String oid) {
		byte[] startRow = null;
		byte[] stopRow = null;
		startRow = Bytes.add(new byte[]{(byte)this.getNum()}, Bytes.toBytes(oid));
		stopRow = Bytes.add(new byte[]{(byte)this.getNum()}, Bytes.toBytes(asciiIncrease(oid)));
		return new byte[][]{startRow,stopRow};
	}
	
	/**
	 * Description: ASCII码递增
	 * 
	 * @Version1.0 2012-6-9 下午04:00:45 by 张红意（hongyi@run.com）创建
	 * @param str 输入参数
	 * @return ASCII码递增后的字符串
	 */
	public static String asciiIncrease(String str) {
		char[] chars = str.toCharArray();
		int a = (int) chars[chars.length - 1] + 1;
		chars[chars.length - 1] = Character.toChars(a)[0];
		return new String(chars);
	}
	/**
	 * Description: 将传入参数进行MD5算法之后取前两个字节, 再与传入参数连接
	 * @Version1.0 2012-6-6 上午11:10:13 by 张红意（hongyi@run.com）创建
	 * 
	 * @param dataid 输入参数
	 * @return 进行MD5算法的字节数组
	 */
	public static byte[] generateMD5(String dataid) {
		byte[] rowkey = null;
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			rowkey = Bytes.add(Bytes.head(md.digest(Bytes.toBytes(dataid)), 2), Bytes.toBytes(dataid));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return rowkey;
	}
	/**
	 * 获得日志表的表名前缀，不同对象类型可以构建不同的日志表，截止当前(2012-09-06)所有对象使用同一个日志表
	 * 如果以后要按照不同对象建不同的日志表可以在不同对象中重写此实现。
	 * @return 日志表表名前缀字符串
	 */
	public String getLogTableNamePrefix() {
		return DEFAULT_LOG_TABLENAME_PREFIX;
	}
	/**
	 * 获得对象基础信息的表名前缀，同上，这个是默认实现。
	 * @return 对象基础信息表名前缀字符串
	 */
	public String getObjInfoTableNamePrefix() {
		return DEFAULT_OBJINFO_TABLENAME_PREFIX;
	}
	/**
	 * 获得每种对象的索引表表名前缀，截止当前(2012-09-06)所有对象使用两张索引表
	 * IP一张，其他对象为另一张，因此为减少编码以下为默认实现，ip类型重写实现
	 */
	public String getIndexTableNamePrefix() {
		return "object_relation";
	}
	public boolean needGroup() {
		return false;
	}
}
